package com.example.broadcast.config;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.corundumstudio.socketio.listener.DataListener;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@org.springframework.context.annotation.Configuration
public class SocketIOConfig {

    private static final Logger log = LoggerFactory.getLogger(SocketIOConfig.class);

    @Value("${socketio.host:0.0.0.0}")
    private String host;

    @Value("${socketio.port:8081}")
    private int port;

    private static final Map<String, FileOutputStream> fileStreams = new HashMap<>();

    @Bean
    public SocketIOServer socketIOServer() {
        Configuration config = new Configuration();
        config.setHostname(host);
        config.setPort(port);
        config.setWorkerThreads(10);
        config.setAllowHeaders("*");
        config.setAllowCustomRequests(true);
        config.setMaxFramePayloadLength(10000000); // 设置最大帧长度为 10 MB
        SocketIOServer server = new SocketIOServer(config);
        server.addListeners(this);//设置启用注解
       /* server.addConnectListener(this::onConnect);
        server.addDisconnectListener(this::onDisconnect);*/
       /* server.addEventListener("video", ByteBuffer.class, new DataListener<ByteBuffer>() {
            @Override
            public void onData(SocketIOClient client, ByteBuffer data, AckRequest ackRequest) {
                System.out.println("Received video data: " + data.remaining() + " bytes");

                // 处理视频数据
                // 例如，可以将数据转发给其他客户端
                for (SocketIOClient otherClient : server.getAllClients()) {
                    System.out.println("11111111111");
                    if (!otherClient.getSessionId().equals(client.getSessionId())) {
                        otherClient.sendEvent("video", data);
                    }
                }
            }
        });*/

        ObjectMapper objectMapper = new ObjectMapper();
        server.addEventListener("video", String.class, new DataListener<String>() {
            @Override
            public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
                try {
                    Map<String, Object> message = objectMapper.readValue(data, Map.class);
                    byte[] payload = (byte[]) message.get("payload");

                    ByteBuffer byteBuffer = ByteBuffer.wrap(payload);
                    System.out.println("Received video data: " + byteBuffer.remaining() + " bytes");
                    // 处理视频数据
                    // 例如，可以将数据转发给其他客户端
                    for (SocketIOClient otherClient : server.getAllClients()) {
                        if (!otherClient.getSessionId().equals(client.getSessionId())) {
                            otherClient.sendEvent("video", byteBuffer);
                        }
                    }
                } catch (Exception e) {
                    log.error("Error processing video data: {}", e.getMessage());
                }
            }
        });
        server.start();
        return server;
    }


    @OnEvent(value = "chat")
    public void handleMessage(SocketIOClient client, String data,AckRequest ackRequest) {
        System.out.println("Received VENT data from client: " + data);
        socketIOServer().getAllClients().forEach(c -> {
            if(!c.getSessionId().equals(client.getSessionId())){
                c.sendEvent("chat", data);
            }
        });
        /*client.sendEvent("chat", "Echo: " + data);*/
    }

    /**
     * 此处注意并发问题
     * @param client
     * @param data
     * @param ackRequest
     */
    @OnEvent(value = "file_chunk")
    public void handleFile(SocketIOClient client, FileChunk data,AckRequest ackRequest) {
        System.out.println("filename:"+data.filename+":thread:"+Thread.currentThread().getName());

        try {
            // 获取或创建文件的 FileOutputStream
            FileOutputStream fos = fileStreams.computeIfAbsent(data.filename, k -> {
                try {
                    return new FileOutputStream(k);
                } catch (IOException e) {
                    log.error("Illegal base64 character: {}", e.getMessage());
                    client.sendEvent("file_error", "Error creating file: " + e.getMessage());
                    return null;
                }
            });
            if (fos != null) {
                // 将 Base64 编码的字符串解码为字节数组
                byte[] decodedChunk = Base64.getDecoder().decode(data.chunk);
                // 写入文件块
                fos.write(decodedChunk);
                fos.flush();
                // 如果所有块都已接收完毕，关闭 FileOutputStream
                if (data.offset + decodedChunk.length >= data.totalSize) {
                    fos.close();
                    fileStreams.remove(data.filename);
                    client.sendEvent("file_received", data.filename);
                    System.out.println("File " + data.filename + " received successfully.");
                }
            }
        } catch (IllegalArgumentException e) {
            log.error("Illegal base64 character: {}", e.getMessage());
            client.sendEvent("file_error", "Illegal base64 character: " + e.getMessage());
        } catch (Exception e) {
            log.error("Illegal base64 character: {}", e.getMessage());
            client.sendEvent("file_error", "Error receiving file: " + e.getMessage());
        }
    }

    @OnConnect
    public void onConnect(SocketIOClient client) {
        System.out.println("Client connected: " + client.getSessionId());
    }

    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        System.out.println("Client disconnected: " + client.getSessionId());
    }


    public static class FileChunk {
        public String userId;
        public String filename;
        public String chunk;
        public int offset;
        public int totalSize;
    }
}